﻿using WizardEngine.Core.Persistence;

namespace WizardEngine.Core
{
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using Specification;

    /// <summary>
    /// Factory for registering and creating named wizards. 
    /// </summary>
    public static class WizardFactory
    {
        private static readonly IDictionary<string, object> Wizards = new Dictionary<string, object>();
        private static IFlowStatePersistenceProvider FlowStatePersistenceProvider;

        /// <summary>
        /// Configures the factory.
        /// </summary>
        /// <param name="flowStatePersistenceProvider"></param>
        public static void Configure(IFlowStatePersistenceProvider flowStatePersistenceProvider)
        {
            FlowStatePersistenceProvider = flowStatePersistenceProvider;
        }

        /// <summary>
        /// Registers named wizard for further creation.
        /// </summary>
        /// <typeparam name="T">Specific custom flow state type. Must match with flow state instance type being loaded. </typeparam>
        /// <param name="name">Wizard name. </param>
        /// <param name="specification">Flow specification. </param>
        public static void Register<T>(string name, IFlowSpecification<T> specification) where T : FlowState, new()
        {
            Contract.Assert(!string.IsNullOrEmpty(name));
            Contract.Assert(!Wizards.ContainsKey(name));
            Contract.Assert(specification != null);
            Contract.Assert(specification.IsValid);
            Contract.Assert(FlowStatePersistenceProvider != null);

            var wizard = new Wizard<T>(specification, FlowStatePersistenceProvider);
            Wizards.Add(name, wizard);
        }

        /// <summary>
        /// Creates wizard of given name. 
        /// </summary>
        /// <remarks>
        /// Wizard of given name needs to be registered first to be created.
        /// </remarks>
        /// <typeparam name="T">Specific custom flow state type. Must match with flow state instance type being loaded. </typeparam>
        /// <param name="name">Wizard name. </param>
        /// <returns>Wizard of given name. </returns>
        public static IWizard<T> Create<T>(string name) where T : FlowState, new()
        {
            Contract.Assert(!string.IsNullOrEmpty(name));
            Contract.Assert(Wizards.ContainsKey(name));

            return Wizards[name] as IWizard<T>;
        }
    }
}
